home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 April: Mac OS SDK / Dev.CD Apr 99 SDK1.toast / Development Kits / Thread Manager / Thread Manager 2.1.1d1+ / ThreadedSort / Sprocket / Lib / DialogUtils.cp < prev    next >
Encoding:
Text File  |  1995-04-28  |  10.1 KB  |  395 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        DialogUtils.cp
  3.  
  4.     Contains:    Auto-sized error alert mechanism,
  5.                 ModalFilterProcs which correctly handle events,
  6.                 and Standard “Close Document” dialogs. 
  7.  
  8.     Written by: Dave Falkenburg
  9.  
  10.     Copyright:    © 1993-94 by Dave Falkenburg, all rights reserved.
  11.  
  12.     Change History (most recent first):
  13.      
  14.          <5>    11/16/94    DRF        Added explicit #include <SegLoad.h> for latest universal
  15.                                     headers. Also added cast to keep MPW CFront happier.
  16.          <4>    11/16/94    DRF        Add StdFilterProc for THINK C.
  17.          <3>     9/27/94    DRF         AppLib.h is now Sprocket.h
  18.          <2>      9/9/94    DRF        Reordered headers and removed redundant #includes.
  19.  */
  20.  
  21. #include "Sprocket.h"
  22.  
  23. #include <Fonts.h>
  24. #include <Resources.h>
  25. #include <TextUtils.h>
  26. #include <Threads.h>        //    For YieldToAnyThread()
  27. #include <StandardFile.h>    //    For ModalFilterYDProcPtr
  28. #include <SegLoad.h>        //    For ExitToShell()
  29.  
  30. #if GENERATINGCFM
  31. QDGlobals    qd;
  32. #endif
  33.  
  34. //    Some types which should probably be defined in <Dialogs.h>
  35. //    NOTE: These must be aligned on 2-byte boundaries
  36. #if defined(powerc) || defined (__powerc)
  37. #pragma options align=mac68k
  38. #endif
  39.  
  40. struct DialogItem
  41.     {
  42.     long    usedByDialogManager;
  43.     Rect    boundsRect;
  44.     char    type;
  45.     char    length;
  46.     };
  47.  
  48. struct DialogItemList            //    a.k.a. a 'DITL'
  49.     {
  50.     short        count;
  51.     DialogItem    firstItem[1];
  52.     };
  53.  
  54. //    Restore default alignment
  55. #if defined(powerc) || defined(__powerc)
  56. #pragma options align=reset
  57. #endif
  58.  
  59. typedef    DialogItem        *DialogItemPtr;
  60. typedef    DialogItemList    **DialogItemListHandle;
  61. typedef    DialogTemplate    **DialogTemplateHandle;
  62.  
  63. #ifndef    powerc
  64. #ifdef    __SC__
  65.  
  66. #ifdef __CFM68K__
  67. #pragma lib_export on
  68. #endif
  69.  
  70. extern pascal OSErr GetStdFilterProc(ModalFilterUPP *theProc)
  71.  THREEWORDINLINE(0x303C, 0x0203, 0xAA68);
  72.  
  73. #ifdef __CFM68K__
  74. #pragma lib_export off
  75. #endif
  76.  
  77. pascal Boolean
  78. StdFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  79.     {
  80.     ModalFilterUPP    filterUPP;
  81.  
  82.     //    Dialogs.h
  83.     
  84.     (void) GetStdFilterProc(&filterUPP);
  85.  
  86.     return    CallModalFilterProc(filterUPP,theDialog,anEvent,itemHit);
  87.     }
  88.  
  89. #endif
  90. #endif
  91.  
  92. //    private function Prototypes
  93.  
  94. static    pascal Boolean    StandardDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  95. static    pascal Boolean    StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit, void * yourData);
  96. static    pascal Boolean    StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  97. static    Boolean            FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  98.  
  99.  
  100.  
  101. ///////////////////////////////////////////////////////////
  102. //
  103. //    StandardAlert
  104. //
  105. //    An alternative to Alert() which uses the extended
  106. //    Dialog Manager capabilities.
  107. //
  108. //    I’m not sure we really need this call, but it seems
  109. //    to do the trick just fine.
  110.  
  111. short
  112. StandardAlert(    short dlogID,
  113.                 short defaultItem,                /* = ok */
  114.                 short cancelItem,                /* = 0 */
  115.                 ModalFilterUPP customFilterProc    /* = nil */)
  116.     {
  117.     DialogPtr        theDialog;
  118.     short            itemHit = 0;
  119.     ModalFilterUPP    filterToUse;
  120.     
  121.     HiliteWindowsForModalDialog(false);
  122.  
  123.     theDialog = GetNewDialog(dlogID,nil,(WindowPtr) -1);
  124.     if (defaultItem)
  125.         SetDialogDefaultItem(theDialog,defaultItem);
  126.     if (cancelItem)
  127.         SetDialogCancelItem(theDialog,cancelItem);
  128.  
  129.     if (customFilterProc)
  130.         filterToUse = customFilterProc;
  131.     else
  132.         filterToUse = StandardDialogFilter;
  133.  
  134.     do
  135.         ModalDialog(filterToUse,&itemHit);
  136.     while (itemHit == 0);
  137.     
  138.     DisposeDialog(theDialog);
  139.  
  140.     HiliteWindowsForModalDialog(true);
  141.  
  142.     return itemHit;
  143.     }
  144.  
  145.  
  146. ///////////////////////////////////////////////////////////
  147. //
  148. //    ErrorAlert
  149. //
  150. //    A nice error reporting routine which presents an
  151. //    auto-sized alert box containing the supplied text.
  152. //
  153. //    NOTE:    This routine ASSUMES the following 'DITL'
  154. //            structure:
  155. //
  156. //            item #1 : an “OK” button
  157. //            item #2 : a static text item, somewhere above #1
  158. //
  159. //    NOTE:    We probably need to worry more about low
  160. //            memory conditions-- this can probably
  161. //            be handled by a custom GrowZoneProc and
  162. //            reserve memory area large enough to hold
  163. //            all the space we’d need.
  164. //
  165.  
  166. void
  167. ErrorAlert(short stringList,short whichString)
  168.     {
  169.     Str255                    errorString;
  170.     GrafPtr                    oldPort,windowMgrPort;
  171.     short                    oldFont;
  172.     DialogTemplateHandle    errorDialogTemplate;
  173.     DialogItemListHandle    errorDialogItems;
  174.     TEHandle                aTEHandle;
  175.     Rect                    textRect;
  176.     short                    textHeight;
  177.     short                    additionalSpaceNeeded;
  178.     DialogItemPtr            okButtonItem,errorTextItem;
  179.     const StringPtr            nullStr = (StringPtr) "\p";
  180.  
  181.     GetIndString(errorString,stringList,whichString);
  182.     
  183.     errorDialogTemplate = (DialogTemplateHandle) Get1Resource('DLOG',kErrorAlertID);
  184.     HLock((Handle) errorDialogTemplate);
  185.     
  186.     errorDialogItems = (DialogItemListHandle) Get1Resource('DITL',(**errorDialogTemplate).itemsID);
  187.     HLock((Handle) errorDialogItems);
  188.     
  189.     //    Find the dialog items
  190.     
  191.     okButtonItem = (**errorDialogItems).firstItem;
  192.     errorTextItem = (DialogItemPtr) ((Ptr) okButtonItem + sizeof(DialogItem) + okButtonItem->length);
  193.     
  194.     GetPort(&oldPort);
  195.     GetWMgrPort(&windowMgrPort);
  196.     SetPort(windowMgrPort);
  197.     oldFont = qd.thePort->txFont;
  198.     TextFont(systemFont);
  199.  
  200.     aTEHandle = TENew(&textRect,&textRect);
  201.     TESetText(&errorString[1],errorString[0],aTEHandle);
  202.     textHeight = (*aTEHandle)->lineHeight * (*aTEHandle)->nLines;
  203.     TEDispose(aTEHandle);
  204.  
  205.     additionalSpaceNeeded = textHeight - (errorTextItem->boundsRect.bottom
  206.                             - errorTextItem->boundsRect.top);
  207.  
  208.     if (additionalSpaceNeeded > 0)
  209.         {
  210.         (**errorDialogTemplate).boundsRect.bottom += additionalSpaceNeeded;
  211.         errorTextItem->boundsRect.bottom += additionalSpaceNeeded;
  212.         OffsetRect(&okButtonItem->boundsRect,0,additionalSpaceNeeded);
  213.         }
  214.         
  215.     TextFont(oldFont);
  216.     SetPort(oldPort);
  217.     
  218.     InitCursor();
  219.     ParamText(errorString,nullStr,nullStr,nullStr);
  220.  
  221.     (void) StandardAlert(kErrorAlertID);
  222.  
  223.     ReleaseResource((Handle) errorDialogTemplate);
  224.     ReleaseResource((Handle) errorDialogItems);
  225.     }
  226.  
  227.  
  228. ///////////////////////////////////////////////////////////
  229. //
  230. //    FatalErrorAlert
  231. //
  232. //    A companion to ErrorAlert which also kills the process.
  233. //
  234.  
  235. void
  236. FatalErrorAlert(short stringList,short whichString)
  237.     {
  238.     ErrorAlert(stringList,whichString);
  239.     ExitToShell();
  240.     }
  241.  
  242.  
  243. ///////////////////////////////////////////////////////////
  244. //
  245. //    StandardDialogFilter and StandardDialogFilterYD
  246. //
  247. //    These function takes care of routing events not meant
  248. //    for the dialog window to other parts of the application.
  249. //
  250. //    Use them as an alternative to passing a NIL ModalFilterProc
  251. //    to ModalDialog() and CustomGet(Put)File. Unlike the default
  252. //    filter, these routines properly processes update events
  253. //    to keep background processes running.
  254. //
  255. //    The Thread Manager, if present, is also called to yield
  256. //    control to other cooperative threads within the process.
  257. //
  258. //    Because of pascal calling conventions we need two separate
  259. //    routines, but this is minimized by sharing implementation
  260. //    in FilterProcCommon.
  261. //
  262.  
  263. ModalFilterUPP    StandardDialogFilter
  264. = NewModalFilterProc(StandardDialogFilterProc);
  265.  
  266. ModalFilterYDUPP    StandardDialogFilterYD
  267. = NewModalFilterYDProc(StandardDialogFilterYDProc);
  268.  
  269. ModalFilterUPP    StandardCloseDialogFilter
  270. = NewModalFilterProc(StandardCloseDialogFilterProc);
  271.  
  272.  
  273. pascal Boolean
  274. StandardDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  275.     {
  276.     //    Call through common code to check for events we’d like to handle.
  277.     //    If that is unsuccessful, call through the System 7 StdFilterProc
  278.     //    to handle CR, “CMD-.” & ESC in an international-friendly manner.
  279.  
  280.     if (FilterProcCommon(theDialog, anEvent, itemHit))
  281.         return true;
  282.     else
  283.         return (StdFilterProc(theDialog, anEvent, itemHit));
  284.     }
  285.  
  286.  
  287. pascal Boolean
  288. StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit, void * /*unusedData*/)
  289.     {
  290.     //    We don’t call through to StdFilterProc since the
  291.     //    Standard File Package already does everything we need.
  292.  
  293.     return FilterProcCommon(theDialog, anEvent, itemHit);
  294.     }
  295.  
  296. void
  297. PseudoClickInDialogItem(DialogPtr theDialog, short itemToClick)
  298.     {
  299.     Handle    itemHandle;
  300.     Rect    itemBox;
  301.     long    finalTicks;
  302.     short    itemType;
  303.     
  304.     GetDialogItem(theDialog,itemToClick,&itemType,&itemHandle,&itemBox);
  305.  
  306.     HiliteControl((ControlHandle) itemHandle,inButton);
  307.     Delay(8,&finalTicks);
  308.     HiliteControl((ControlHandle) itemHandle,0);
  309.     }
  310.  
  311.  
  312. pascal Boolean
  313. StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  314.     {
  315.     if ((anEvent->what == keyDown))
  316.         {
  317.         char    c = (char) anEvent->message & charCodeMask;
  318.         
  319.         if ((c == 'd') || (c == 'D'))                //    NOT INTERNATIONAL FRIENDLY!!!
  320.             {
  321.             *itemHit = kDontSaveDocument;
  322.             PseudoClickInDialogItem(theDialog,kDontSaveDocument);
  323.             return true;
  324.             }
  325.         }
  326.  
  327.     //    Return through the common code above so that default item processing can happen
  328.     return StandardDialogFilterProc(theDialog, anEvent, itemHit);
  329.     }
  330.  
  331.  
  332. Boolean
  333. FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * /* itemHit */)
  334.     {
  335.     switch (anEvent->what)
  336.         {
  337.         case updateEvt:
  338.         case activateEvt:
  339.             //     Update or activate for the dialog window?
  340.             if (theDialog == (DialogPtr) anEvent->message)
  341.                 break;
  342.  
  343.             //    no, fall through to HandleEvent            
  344.             
  345.         case diskEvt:
  346.             HandleEvent(anEvent);
  347.             return(false);
  348.  
  349.         default:
  350.             break;        
  351.         }
  352.  
  353.     if (gHasThreadManager)        //    If we have threads, let them run!
  354.         YieldToAnyThread();
  355.  
  356.     return false;                //    We didn’t handle the event
  357.     }
  358.  
  359.  
  360. //////////////////////////////////////////////////////////////////
  361. //
  362. //    StandardCloseDocument
  363. //
  364. //    Provides the standard human interface for closing a document
  365. //
  366. //    NOTE: When we make TDocument class, this will become a method
  367. //          and probably won’t need any parameters.
  368. //
  369. //    NOTE:    StandardCloseResult matches the dialog items for 
  370.  
  371. StandardCloseResult
  372. StandardCloseDocument(const StringPtr documentType, StringPtr documentName,
  373.                       Boolean hasNewEditions, Boolean quitting)
  374.     {
  375.     short        whichAlert;
  376.     short        whichString;
  377.     StringPtr    nullStr = (StringPtr) "\p";
  378.     Str255        reasonForClosingStr;
  379.  
  380.     if (hasNewEditions)
  381.         whichAlert = kStandardCloseWithNewPubsAlertID;
  382.     else
  383.         whichAlert = kStandardCloseAlertID;
  384.     
  385.     if (quitting)
  386.         whichString = kQuittingStr;
  387.     else
  388.         whichString = kClosingStr;
  389.  
  390.     GetIndString(reasonForClosingStr,kStandardCloseStrings,whichString);
  391.     ParamText(documentType,documentName,reasonForClosingStr,nullStr);
  392.     
  393.     return ((StandardCloseResult) StandardAlert(whichAlert,kSaveDocument,kCancelSaveDocument,StandardCloseDialogFilter));
  394.     }
  395.